﻿using System;

namespace MathService
{
    public partial struct Complex
    {
        /* -------------------------------------------------------------------------------------------- */

        public static class Trigonomerty
        {
            public static Complex Sin(Complex z)
            {
                var re = z.Re;
                var im = z.Im;
                if(im.Equals(0)) return new Complex(Math.Sin(re));
                var eb = Math.Exp(im);
                var eb_inv = 1 / eb;
               
                return new Complex(.5 * Math.Sin(re) * (eb_inv + eb), .5 * Math.Cos(re) * (eb - eb_inv));
            }

            public static Complex Cos(Complex z)
            {
                var re = z.Re;
                var im = z.Im;
                if(im.Equals(0)) return new Complex(Math.Cos(re));
                var eb = Math.Exp(im);
                var eb_inv = 1 / eb;

                return new Complex(.5 * Math.Cos(re) * (eb_inv + eb), .5 * Math.Sin(re) * (eb_inv - eb));
            }

            public static Complex tg(Complex z)
            {
                var re = z.Re;
                var im = z.Im;
                if(im.Equals(0)) return new Complex(Math.Sin(re) / Math.Cos(re));

                re *= 2;
                im *= 2;

                var sin2Re = Math.Sin(re);
                var sinh2Im = Math.Sinh(im);
                var cos2Re_cosh2Im = Math.Cos(re) + Math.Cosh(im);

                return new Complex(sin2Re / cos2Re_cosh2Im, sinh2Im / cos2Re_cosh2Im);
            }

            public static Complex ctg(Complex z)
            {
                var re = z.Re;
                var im = z.Im;
                if(im.Equals(0)) return new Complex(Math.Sin(re) / Math.Cos(re));

                var sinRe = Math.Sin(re);
                var cosRe = Math.Cos(re);
                im *= 2;
                re *= 2;
                var sin2Im = Math.Sinh(im);
                var cos2Re_cosh2Im = Math.Cos(re) - Math.Cosh(im);

                return new Complex(2 * cosRe * sinRe / cos2Re_cosh2Im, sin2Im / cos2Re_cosh2Im);
            }

            public static class Hyperbolic
            {
                public static Complex Sh(Complex z)
                {
                    var re = z.Re;
                    var im = z.Im;
                    if(im.Equals(0)) return Math.Sinh(re);
                    var sinhRe = Math.Sinh(re);
                    var coshRe = Math.Cosh(re);
                    var sinIm = Math.Sin(im);
                    var cosIm = Math.Cos(im);

                    return new Complex(sinhRe * cosIm, coshRe * sinIm);
                }

                public static Complex Ch(Complex z)
                {
                    var re = z.Re;
                    var im = z.Im;
                    if(im.Equals(0)) return Math.Cosh(re);
                    var sinhRe = Math.Sinh(re);
                    var coshRe = Math.Cosh(re);
                    var sinIm = Math.Sin(im);
                    var cosIm = Math.Cos(im);

                    return new Complex(coshRe * cosIm, sinhRe * sinIm);
                }

                public static Complex tgh(Complex z)
                {
                    var re = z.Re;
                    var im = z.Im;
                    if(im.Equals(0)) return Math.Tanh(re);

                    var coshRe = Math.Cosh(re);
                    var sinhRe = Math.Sinh(re);
                    im *= 2;
                    re *= 2;
                    var sin2Im = Math.Sin(im);
                    var cos2Im_cosh2Re = Math.Cos(2 * im) + Math.Cosh(2 * re);

                    return new Complex(2 * coshRe * sinhRe / cos2Im_cosh2Re, sin2Im / cos2Im_cosh2Re);
                }

                public static Complex ctgh(Complex z)
                {
                    var re = z.Re;
                    var im = z.Im;
                    if(im.Equals(0)) return Math.Tanh(re);

                    var coshRe = Math.Cosh(re);
                    var sinhRe = Math.Sinh(re);
                    im *= 2;
                    re *= 2;
                    var sin2Im = Math.Sin(im);
                    var cos2Im_cosh2Re = Math.Cos(2 * im) - Math.Cosh(2 * re);

                    return new Complex(2 * coshRe * sinhRe / cos2Im_cosh2Re, sin2Im / cos2Im_cosh2Re);
                }
            }
        }

    }
}
